﻿using Microsoft.Xna.Framework;
using RaptorEngine;
using RaptorEngine.Components;
using RaptorEngine.Components.CollidableComponent;

namespace OilRigSumoWrestlers.Actions
{
	class NormalBounce : CollisionAction
	{

		public NormalBounce(float remainingEnergy)
		{
			RemainingEnergy = new Vector3(remainingEnergy);
			RemainingEnergy.Y = 1;
		}

        /// <summary>
		/// Handles collision between two boundingSpheres with newton physics solid spheres with 1-remainingEnergy lost. 
        /// </summary>
        /// <param name="ownEntity">The parent entity of the action</param>
        /// <param name="ownVolume">The parent bounding volume of the action</param>
        /// <param name="othersEntity">The other colliding entity</param>
        /// <param name="othersVolume">The boundingVolume of the other entity</param>
        public override void HandleCollision(Entity ownEntity, BoundingVolume ownVolume, Entity othersEntity,
                                    BoundingVolume othersVolume)
		{
            if(othersVolume.CollisionTypes.Contains((int)CollisionType.Bounce))
            {
			    // If the result has been calculated by another action. Just reset and return.
			    if (ownVolume.IsCalculated || ownVolume.CollisionTypes.Contains((int)CollisionType.Ground) || othersVolume.CollisionTypes.Contains((int)CollisionType.Ground))
			    {
				    return;
			    }

			    float mass1 = -1, mass2 = -1;
			    Vector3 vel1 = Vector3.Zero, vel2 = Vector3.Zero;

			    // Get the direction
			    Vector3 dir = ownEntity.Position - othersEntity.Position;

			    // Move the objects to position just before collision to avoid objects 
			    // getting stuck (colliding while moving away from each other).
			    float intersectLength = ownVolume.Radius + othersVolume.Radius - dir.Length();

			    // Normalize the direction
			    dir.Normalize();

				if (ownEntity.HasComponent(ComponentType.Movable))
			    {
				    ownEntity.Position += intersectLength * dir;
			    }
			    else if(ownEntity.HasComponent(ComponentType.Movable))
			    {
				    othersEntity.Position += intersectLength * dir;
			    }

				if (ownEntity.HasComponent(ComponentType.Particle))
				{
					ParticleComp part = ((ParticleComp)ownEntity.GetComponent(ComponentType.Particle));
					for (int i = 0; i < UseParticels(ownEntity, othersEntity); i++)
					{
						if (i == 0)
						{
							//GameEngine.Instance.Audio.PlaySound("player_hit", .5f);
                            GameEngine.Instance.Audio.Play3DSound("player_hit", 1f, othersEntity.Position);
						}
						part.AddParticles("bouncingSmoke", ownEntity.Position - ownVolume.Radius * dir, Vector3.Zero);
					}
				}


			    // If the entity has mass and velocity info, use it. If not, it wont be used later on.
			    if (ownEntity.HasComponent(ComponentType.Movable))
			    {
				    mass1 = ((Movable)ownEntity.GetComponent(ComponentType.Movable)).Mass;
				    vel1 = ((Movable)ownEntity.GetComponent(ComponentType.Movable)).Velocity;
			    }

			    float x1 = Vector3.Dot(dir, vel1);
			    Vector3 v1x = dir*x1;
			    Vector3 v1y = vel1 - v1x;

			    // If the entity has mass and velocity info, use it. If not, it wont be used later on.
			    if (othersEntity.HasComponent(ComponentType.Movable))
			    {
				    mass2 = ((Movable)othersEntity.GetComponent(ComponentType.Movable)).Mass;
				    vel2 = ((Movable)othersEntity.GetComponent(ComponentType.Movable)).Velocity;
			    }

			    float x2 = Vector3.Dot(dir, vel2);
			    Vector3 v2x = dir*x2;
			    Vector3 v2y = vel2 - v2x;

			    // If both entities can move apply newton physics to calculate the new velocity for both of them.
			    if (ownEntity.HasComponent(ComponentType.Movable) && othersEntity.HasComponent(ComponentType.Movable))
			    {
				    ((Movable)ownEntity.GetComponent(ComponentType.Movable)).Velocity = (v1x * (mass1 - mass2) / (mass1 + mass2) + v2x * (2 * mass2) / (mass1 + mass2) + v1y) * RemainingEnergy;
				    ((Movable)othersEntity.GetComponent(ComponentType.Movable)).Velocity = (v1x * (2 * mass1) / (mass1 + mass2) + v2x * (mass2 - mass1) / (mass1 + mass2) + v2y) * RemainingEnergy;
			    }

			    // If one of the entities can move it will have the same velocity just in another direction.
			    else if (ownEntity.HasComponent(ComponentType.Movable))
			    {
				    Movable mov = (Movable) ownEntity.GetComponent(ComponentType.Movable);
				    mov.Velocity = Vector3.Reflect(mov.Velocity, dir) * RemainingEnergy;
			    }
			    else if (othersEntity.HasComponent(ComponentType.Movable))
			    {
				    Movable mov = (Movable)othersEntity.GetComponent(ComponentType.Movable);
				    mov.Velocity = Vector3.Reflect(mov.Velocity, dir) * RemainingEnergy;
			    }

			    // This action handles entity2's outcome.
			    othersVolume.IsCalculated = true;
            }
		}

		private int UseParticels(Entity ownEntity, Entity othersEntity)
		{
			float totalVelocity = 0;
			if (ownEntity.HasComponent(ComponentType.Movable))
			{
				totalVelocity += ((Movable)ownEntity.GetComponent(ComponentType.Movable)).Velocity.Length();
			}
			if (othersEntity.HasComponent(ComponentType.Movable))
			{
				totalVelocity += ((Movable)othersEntity.GetComponent(ComponentType.Movable)).Velocity.Length();
			}

			totalVelocity = (totalVelocity < 0.012f) ? 0 : totalVelocity;

			return (int)(totalVelocity*150);
		}
	}
}
